﻿#include "fcgiplus.hpp"
#include "eiendb.hpp"
#include "eiennet.hpp"
#include "eiengd.hpp"
#include "eienexpr.hpp"
#include "eientpl.hpp"
#include "fcgiserv.hpp"
#include <iostream>
using namespace std;
using namespace winux;
using namespace eiendb;
using namespace eiennet;
using namespace eiengd;
using namespace eienexpr;
using namespace eientpl;
using namespace fcgi;


class TemplateLangExpText
{
public:
    static void Init() {
        cout << "TPLEMath Init" << endl;
        __initExprFuncs();
    }
    static void Dispose() {
        //应该不需要吧
    }

    private:
    // cutstring(str,maxLength)
    static bool __FuncCutString( std::vector<eienexpr::Expression *> & params, winux::SimplePointer<eienexpr::ExprOperand> * outRetValue, void * data )
    {
        outRetValue->attachNew(NULL);
        if ( params.size() != 2 )
        {
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`cutstring(str,maxLength)` parameters must has 2 args!" );
            return false;
        }
        Mixed const & v1 = params[0]->val();
        Mixed const & v2 = params[1]->val();
        if ( !v1.isString() || !v2.isInteger() )
        {
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`cutstring(str,maxLength)` parameters wrong!" );
            return false;
        }
        String text = (String)v1;
        int maxCount = (int)v2;
        text = text.substr( 0, maxCount );

        outRetValue->attachNew( new eienexpr::ExprLiteral( text ) );

        return true;
    }
    static void __initExprFuncs()
    {
        // cutstring(str,maxLength)
        eienexpr::ExprFunc::SetFunc( "cutstring", TemplateLangExpText::__FuncCutString );
    }
};




class MVec4 {
    Mixed __data;
public:
    MVec4( float x=0.0f, float y=0.0f, float z=0.0f, float w=0.0f )
    {
        __data.createArray();
        __data.add()(0.0)(0.0)(0.0)(0.0);
        __data[0] = x;
        __data[1] = y;
        __data[2] = z;
        __data[3] = w;
    }
    MVec4( Mixed const& point ) {
        __data.createArray();
        __data.add()(0.0)(0.0)(0.0)(0.0);
        __data[0] = (point.has("x")?(float)point["x"]:(point.has("r")?(float)point["r"]:0.0f) );
        __data[1] = (point.has("y")?(float)point["y"]:(point.has("g")?(float)point["g"]:0.0f) );
        __data[2] = (point.has("z")?(float)point["z"]:(point.has("b")?(float)point["b"]:0.0f) );
        __data[3] = (point.has("w")?(float)point["w"]:(point.has("a")?(float)point["a"]:0.0f) );
        cout << "MVec4:build:" << __data.json() << point.json() << endl;
    }
    inline float x() const { return (float) __data[0]; }
    inline float y() const { return (float) __data[1]; }
    inline float z() const { return (float) __data[2]; }
    inline float w() const { return (float) __data[3]; }
    inline MVec4 xy() const { return MVec4( x(), y() ); }
    inline MVec4 xyz() const { return MVec4( x(), y(), z() ); }

    inline float r() const { return (float) __data[0]; }
    inline float g() const { return (float) __data[1]; }
    inline float b() const { return (float) __data[2]; }
    inline float a() const { return (float) __data[3]; }
    inline MVec4 rgb() const { return MVec4( r(), g(), b() ); }

    inline void x( float val ) { __data[0] = val; }
    inline void y( float val ) { __data[1] = val; }
    inline void z( float val ) { __data[2] = val; }
    inline void w( float val ) { __data[3] = val; }
    inline void xyz( MVec4 & tar ) {
        __data[0] = tar.x();
        __data[1] = tar.y();
        __data[2] = tar.z();
    }

    inline void r( float val ){ __data[0] = val; }
    inline void g( float val ){ __data[1] = val; }
    inline void b( float val ){ __data[2] = val; }
    inline void a( float val ){ __data[3] = val; }
    inline void rgb( MVec4 & tar ) {
        __data[0] = tar.r();
        __data[1] = tar.g();
        __data[2] = tar.b();
    }
};


class TemplateLangExpMath
{
public:
    static void Init() {
        cout << "TPLEMath Init" << endl;
        __initExprFuncs();
    }
    static void Dispose() {
    }

    private:
    // random(n1,n2)
    static bool __FuncRandom( std::vector<eienexpr::Expression *> & params, winux::SimplePointer<eienexpr::ExprOperand> * outRetValue, void * data )
    {
        outRetValue->attachNew(NULL);
        if ( params.size() == 2 )
        {
            int n1 = params[0]->val();
            int n2 = params[1]->val();
            outRetValue->attachNew( new eienexpr::ExprLiteral( winux::Random(n1,n2) ) );
            return true;
        }
        else
        {
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`random()` parameters wrong!" );
        }
        return false;
    }
    static bool __containPP( MVec4 const& p1, MVec4 const& p2 ) {
        return p1.x() == p2.x() && p1.y() == p2.y();
    }
    static bool __containPR( MVec4 const& p1, MVec4 const& r1 ) {
        return p1.x() >= r1.x() && p1.x() < r1.x() + r1.z() && p1.y() >= r1.y() && p1.y() < r1.y() + r1.w();
    }
    static bool __containRR( MVec4 const& r1, MVec4 const& r2 ) {
        MVec4 p1( r2.x() + r2.z(), r2.y() );
        MVec4 p2( r2.x(), r2.y() + r2.w() );
        MVec4 p3( r2.x()+r2.z(), r2.y()+r2.w() );

        return TemplateLangExpMath::__containPR(r2.xy(), r1) || TemplateLangExpMath::__containPR(p1, r1) || TemplateLangExpMath::__containPR(p2, r1) || TemplateLangExpMath::__containPR(p3, r1);
    }
    // contain_pp(p1,p2)
    static bool __FuncContainPointPoint( std::vector<eienexpr::Expression *> & params, winux::SimplePointer<eienexpr::ExprOperand> * outRetValue, void * data )
    {
        outRetValue->attachNew(NULL);
        if ( params.size() != 2 )
        {
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`contain_pp(p1,p2)` parameters must has 2 point!" );
            return false;
        }
        Mixed const & mp1 = params[0]->val();
        Mixed const & mp2 = params[1]->val();
        if ( !mp1.isCollection() || !mp2.isCollection())
        {
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`contain_pp(p1,p2)` parameters wrong!" );
            return false;
        }
        MVec4 p1( mp1 );
        MVec4 p2( mp2 );

        outRetValue->attachNew( new eienexpr::ExprLiteral( TemplateLangExpMath::__containPP( p1, p2 ) ) );

        return true;
    }
    // contain_pr(p1,r1)
    static bool __FuncContainPointRect( std::vector<eienexpr::Expression *> & params, winux::SimplePointer<eienexpr::ExprOperand> * outRetValue, void * data )
    {
        cout << "__FuncContainPointRect, running" << endl;
        outRetValue->attachNew(NULL);
        if ( params.size() != 2 )
        {
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`contain_pr(p1,r1)` parameters must has 2 point!" );
            return false;
        }
        Mixed const & mp1 = params[0]->val();
        Mixed const & mr1 = params[1]->val();
        if ( !mp1.isCollection() || !mr1.isCollection() )
        {
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`contain_pr(p1,r1)` parameters wrong!" );
            return false;
        }

        MVec4 p1( mp1 );
        MVec4 r1( mr1 );
        
        outRetValue->attachNew( new eienexpr::ExprLiteral( TemplateLangExpMath::__containPR( p1, r1 ) ) );

        return true;
    }
    // contain_rr(r1,r2)
    static bool __FuncContainRectRect( std::vector<eienexpr::Expression *> & params, winux::SimplePointer<eienexpr::ExprOperand> * outRetValue, void * data )
    {
        outRetValue->attachNew(NULL);
        if ( params.size() != 2 )
        {
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`contain_rr(r1,r2)` parameters must has 2 point!" );
            return false;
        }
        Mixed const & mr1 = params[0]->val();
        Mixed const & mr2 = params[1]->val();
        if ( !mr1.isCollection() || !mr2.isCollection() )
        {
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`contain_rr(r1,r2)` parameters wrong!" );
            return false;
        }

        MVec4 r1( mr1 );
        MVec4 r2( mr2 );
        
        outRetValue->attachNew( new eienexpr::ExprLiteral( TemplateLangExpMath::__containRR( r1, r2 ) ) );

        return true;
    }
    static void __initExprFuncs()
    {
        // random(n1,n2)
        eienexpr::ExprFunc::SetFunc( "random", TemplateLangExpMath::__FuncRandom );
        // contain_pp(p1,p2)
        eienexpr::ExprFunc::SetFunc( "contain_pp", TemplateLangExpMath::__FuncContainPointPoint );
        // contain_pr(p1,r1)
        eienexpr::ExprFunc::SetFunc( "contain_pr", TemplateLangExpMath::__FuncContainPointRect );
        //contain_rr(r1,r2)
        eienexpr::ExprFunc::SetFunc( "contain_rr", TemplateLangExpMath::__FuncContainRectRect );
    }
};




class TemplateLangExpMixed
{
public:
    static void Init() {
        __initExprFuncs();
    }
    static void Dispose() {
    }

    private:
    // random(n1,n2)
    static String __levelString( int level ) {
        String levelSpace = "";
        for(int i=0;i<level;i++){
            levelSpace += " ";
        }
        return levelSpace;
    }
    static String __showArray( Mixed const& arr, int level ) {
        String levelSpace = TemplateLangExpMixed::__levelString( level );

        String out = "";
        out += levelSpace + "[\n";

        levelSpace = TemplateLangExpMixed::__levelString( ++level );
        int count = arr.getCount();
        for( int i=0; i<count; i++ ) {
            Mixed const& kv = arr[i];
            out += levelSpace;
            
            switch( kv.type() ) {
                case Mixed::MT_ARRAY :
                    out += TemplateLangExpMixed::__showArray( kv, level );
                break;
                case Mixed::MT_INT :
                    out += Format("%d",(int)kv);
                break;
                case Mixed::MT_INT64 :
                    out += Format("%ld",(int64)kv);
                break;
                case Mixed::MT_FLOAT :
                    out += Format("%f",(float)kv);
                break;
                case Mixed::MT_DOUBLE :
                    out += Format("%lf",(double)kv);
                break;
            }
            out += "\n";
        }
        levelSpace = TemplateLangExpMixed::__levelString( --level );
        out += levelSpace + "]";
        return out;
    }
    static bool __FuncShowArray( std::vector<eienexpr::Expression *> & params, winux::SimplePointer<eienexpr::ExprOperand> * outRetValue, void * data )
    {
        outRetValue->attachNew(NULL);
        if( params.size() != 1 ){
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`show_array()` parameters wrong!" );
            return false;
        }

        Mixed const& arr = params[0]->val();
        if( !arr.isArray() ){
            throw eienexpr::ExprError( eienexpr::ExprError::eeFuncParamCountError, "`show_array( arg1 )` arg1 must be array" );
            return false;
        }

    
        String output = TemplateLangExpMixed::__showArray( arr, 0 );
        outRetValue->attachNew( new eienexpr::ExprLiteral( output ) );
        return true;
    }
    static void __initExprFuncs()
    {
        // parse_mixed( mixed )
        eienexpr::ExprFunc::SetFunc( "show_array", TemplateLangExpMixed::__FuncShowArray );
    }
};

int main( int argc, char const * argv[] )
{
#if defined(__GNUC__) && !defined(WIN32) // on linux
    SetLocale::Set("zh_CN.UTF-8");
#endif
    winux::SetLocale __loc__;
    try
    {
// `include/tplexp_text.inc.ecp` embed code is empty!
// `include/tplexp_math.inc.ecp` embed code is empty!
// `include/tplexp_mixed.inc.ecp` embed code is empty!



Template tpl( "template" );

Mixed & arr = tpl.getVarContext()->set("arr");
arr.json(""
"["
"    123,"
"    456,"
"    789,"
"    \"abc\","
"    ["
"        \"a\","
"        0.334,"
"        0.32913809213,"
"        37827489273492734,"
"        \"中文\""
"    ]"
"]"
""
"");

Mixed & p1 = tpl.getVarContext()->set("p1");
Mixed & p2 = tpl.getVarContext()->set("p2");

p1.json("{x:0,y:0}");
p2.json("{x:0,y:0}");

Mixed & text = tpl.getVarContext()->set("text");
text = "12345678901234567890";
// text = "123中文ABC英文4567890ABCDEFGHIJKLMNOPQ";

TemplateLangExpMath::Init();
TemplateLangExpMixed::Init();
TemplateLangExpText::Init();
cout << tpl.output("testText");
TemplateLangExpMath::Dispose();
TemplateLangExpMixed::Dispose();
TemplateLangExpText::Dispose();

    }
    catch ( std::exception const & e )
    {
        cout << e.what() << endl;
    }
    catch (...)
    {
        cout << "Unknown error" << endl;
    }
    return 0;
}

